import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;





public class textToMatrix {
	public static double[][] twoX3={
		{1.0, 2.0, 3.0},
		{4.0, 5.0, 6.0}};
	public static double[][] threeX2={
		{1.0, 2.0},
		{3.0, 4.0},
		{5.0, 6.0}
	};
	public static double[][][] class1Array; 
	public static double[][][] class2Array;
	public static double [][] class1Mean;
	public static double [][] class2Mean;
//	public static double[][] finalArray1;
//	public static double[][] finalArray2;
	private static double[][] multIdentMatrix(int size){
		double[][] matrix=new double[size][size];
		for(int i=0;i<size;i++){
			matrix[i][i]=1.0;
		}
		return matrix;
	}
	private static double[][] addIdentMatrix(int size){
		double[][] matrix=new double[size][size];
		return matrix;
	}
//	private static void textToMatrix() throws FileNotFoundException {
//		int size = -1;
//		File dataFile = new File("bin/textData2015.txt");
//		Scanner countScan = new Scanner(dataFile);
//		while (countScan.hasNext()) {
//			countScan.nextLine();
//			size++;
//		}
//		double[][] array1 = new double[2][size];
//		double[][] array2 = new double[2][size];
//		Scanner dataScan = new Scanner(dataFile);
//		dataScan.nextLine();
//		int i = 0;
//		while (dataScan.hasNext()) {
//			array1[0][i] = Double.parseDouble(dataScan.next());
//			array1[1][i] = Double.parseDouble(dataScan.next());
//			array2[0][i] = Double.parseDouble(dataScan.next());
//			array2[1][i] = Double.parseDouble(dataScan.next());
//			i++;
//		}
//		finalArray1=array1;
//		finalArray2=array2;
//
//	}
	private static void textToMatrixArrays() throws FileNotFoundException {
		int size = -1;
		File dataFile = new File("bin/test2Data.txt");
		Scanner countScan = new Scanner(dataFile);
		while (countScan.hasNext()) {
			countScan.nextLine();
			size++;
		}
		double[][][] array1 = new double[size][2][1];
		double[][][] array2 = new double[size][2][1];
		Scanner dataScan = new Scanner(dataFile);
		dataScan.nextLine();
		int i = 0;
		while (dataScan.hasNext()) {
			array1[i][0][0] = Double.parseDouble(dataScan.next());
			array1[i][1][0] = Double.parseDouble(dataScan.next());
			array2[i][0][0] = Double.parseDouble(dataScan.next());
			array2[i][1][0] = Double.parseDouble(dataScan.next());
			i++;
		}
		class1Array=array1;
		class2Array=array2;

	}
	
	static double[][] add2Matrices(double[][] array1, double[][] array2){
		double[][] answer=new double[array1.length][array1[0].length];
		if(!(array1.length==array2.length&&array1[0].length==array2[0].length))
			System.out.println("Your addition arrays have different demintions");
		for(int i=0;i<array1.length;i++){
			for(int j=0;j<array1[0].length;j++){
				answer[i][j]=array1[i][j]+array2[i][j];
			}
		}
		return answer;
	}
	private static double[][] sub2Matrices(double[][] array1, double[][] array2){
		double[][] answer=new double[array1.length][array1[0].length];
		if(!(array1.length==array2.length&&array1[0].length==array2[0].length))
			System.out.println("Your addition arrays have different demintions");
		for(int i=0;i<array1.length;i++){
			for(int j=0;j<array1[0].length;j++){
				answer[i][j]=array1[i][j]-array2[i][j];
			}
		}
		return answer;
	}
	static double[][] mult2Matrices(double[][] array1, double[][] array2){
		if(array1[0].length!=array2.length){
			System.out.println("M x N from array 1 and N x P in array2 do not have equal Ns");
		}
		double[][] answer=new double[array1.length][array2[0].length];
		for(int i=0;i<array1.length;i++){
			for(int j=0;j<array2[0].length;j++){
				for(int k=0;k<array1[0].length;k++){
					answer[i][j]+=array1[i][k]*array2[k][j];
				}
			}
		}
		return answer;
	}
	static double[][] scalarMult(double[][] array, double scalar){
		double [][] answer=array;
		for(int i=0;i<array.length;i++){
			for(int j=0;j<array[0].length;j++){
				answer[i][j]=array[i][j]*scalar;
			}
		}
		return answer;
	}
	public static void printArray(double[][] array){
		for(int i=0;i<array.length;i++){
			System.out.print("");
			for(int j=0;j<array[0].length;j++){
				if(j<array[0].length-1)
					System.out.print(array[i][j]+"\t ");
				else
					System.out.print(array[i][j]);
			}
			System.out.println("");
		}
	}
	
	public static void printArray(double[] array){
		for(int i=0;i<array.length;i++)
			System.out.println(array[i]);
	}
	
	public static double[][] switchPivot(double[][] array, int turn){
		int pivot=0;
		for(int i=1;i<array.length;i++){
			if(Math.abs(array[i][turn])>Math.abs(array[pivot][turn])){
				pivot=i;
			}
		}
		if(pivot!=0){
			double [] pivotRow=new double[array[0].length];
			double [] firstRow=new double[array[0].length];
			for(int i=turn;i<array[0].length;i++){
				pivotRow[i]=array[pivot][i];
				firstRow[i]=array[turn][i];
			}
			for(int i=turn;i<array[0].length;i++){
				array[turn][i]=pivotRow[i];
				array[pivot][i]=firstRow[i];
			}
		}
		return array;
	}
	
	public static double[] gauss(double[][] A,double[] B)
    {
    		
        int N = B.length;
        for (int k = 0; k < N; k++) 
        {
            /** find pivot row **/
            int pivot = k;
            for (int i = k + 1; i < N; i++) 
                if (Math.abs(A[i][k]) > Math.abs(A[pivot][k])) 
                    pivot = i;
 
            /** swap row in A matrix **/    
            double[] temp = A[k]; 
            A[k] = A[pivot]; 
            A[pivot] = temp;
 
            /** swap corresponding values in constants matrix **/
            double t = B[k]; 
            B[k] = B[pivot];
            B[pivot] = t;
 
            /** pivot within A and B **/
            for (int i = k + 1; i < N; i++) 
            {
                double factor = A[i][k] / A[k][k];
                B[i] -= factor * B[k];
                for (int j = k; j < N; j++) 
                    A[i][j] -= factor * A[k][j];
            }
        }
 
 
        /** back substitution **/
        double[] solution = new double[N];
        for (int i = N - 1; i >= 0; i--) 
        {
            double sum = 0.0;
            for (int j = i + 1; j < N; j++) 
                sum += A[i][j] * solution[j];
            solution[i] = (B[i] - sum) / A[i][i];
        }        
        /** Print solution **/
       return solution;
    }


	private static double[] scalarMult(double[] ds, double scalar) {
		for(int i=0;i<ds.length;i++)
			ds[i]*=scalar;
		return ds;
	}
	
	
	public static void class1VectorMean(double [][][] classArray){
		double xTotal=0.0;
		double yTotal=0.0;
		for(int i=0;i<40;i++){
			xTotal+=classArray[i][0][0];
			yTotal+=classArray[i][1][0];
		}
		class1Mean=new double[2][1];
		class1Mean[0][0]=xTotal/40;
		class1Mean[1][0]=yTotal/40;
				
		//class1Mean[0][0]=(xTotal/40);
		//class1Mean[1][0]=(yTotal/40);
	}
	public static void class2VectorMean(double [][][] classArray){
		double xTotal=0.0;
		double yTotal=0.0;
		for(int i=0;i<40;i++){
			xTotal+=classArray[i][0][0];
			yTotal+=classArray[i][1][0];
		}
		class2Mean=new double[][] {
				{(xTotal/40)}
				,{(yTotal/40)}};
		//class2Mean[0][0]=(xTotal/40);
		//class2Mean[1][0]=(yTotal/40);
	}
	
	public static double[][] transpose(double[][] matrix){
		double[][] answer=new double[matrix[0].length][matrix.length];
		for(int i=0;i<matrix[0].length;i++){
			for(int j=0;j<matrix.length;j++){
				answer[i][j]=matrix[j][i];
			}
		}
		return answer;
	}
	public static double[][] multByTranspose(double[][] matrix){
		return mult2Matrices(matrix, transpose(matrix));
	}
	
	public static double[][] covar(double [][][] subtractedArray){
		double [][] answer=new double[2][2];
		for(int i=0;i<40;i++){
			answer=add2Matrices(answer, multByTranspose(subtractedArray[i]));
		}
		return scalarMult(answer, .025);
	}
	public static double[][] class1Covar= new double[2][2];
	public static double[][] class2Covar= new double[2][2];
	
	public static double gauss2x2(double[][] array){
		return ((array[0][0]*array[1][1])-(array[0][1]*array[1][0]));
	}
	
	public static double class1Determinant=0.0;
	public static double class2Determinant=0.0;

	
	
	
	public static double[][] inverse2x2(double[][] matrix, double determinant){
		double[][] answer=new double [2][2];
		
		answer[0][0]=matrix[1][1];
		answer[0][1]-=matrix[0][1];
		answer[1][0]-=matrix[1][0];
		answer[1][1]=matrix[0][0];
		return(scalarMult(answer, (double)(1/determinant)));
				
	}
	
	public static double determinant(double[][] array) throws Exception {
		double[][] tempArray = new double[array.length][array[0].length];
		for (int i = 0; i < tempArray.length; i++) {
			for (int j = 0; j < tempArray[0].length; j++) {
				tempArray[i][j] = array[i][j];
			}
		}

		int r = 0;
		double determinant;
		double max = 0;
		int pivot = 0;
		double[][] temp1 = new double[1][tempArray[0].length];
		double[][] temp2 = new double[1][tempArray[0].length];

		for (int j = 0; j < tempArray.length; j++) {

			for (int p = j; p < tempArray.length; p++) {
				if (Math.abs(tempArray[p][j]) > max) {
					max = Math.abs(tempArray[p][j]);
					pivot = p;
				}
			}
			if (max == 0) {
				return determinant = 0.0;
			}
			if (pivot > j) {
				r++;
				for (int p = 0; p < tempArray[0].length; p++) {
					temp1[0][p] = tempArray[pivot][p];
					temp2[0][p] = tempArray[j][p];
				}
				for (int p = 0; p < tempArray[0].length; p++) {
					tempArray[j][p] = temp1[0][p];
					tempArray[pivot][p] = temp2[0][p];
				}
			}
			max = 0;
			pivot = 0;
			for (int i = 0; i < tempArray.length; i++) {
				if (i != j) {
					double multiplier = tempArray[i][j] / tempArray[j][j];
					for (int j2 = 0; j2 < tempArray[0].length; j2++) {
						tempArray[i][j2] = tempArray[i][j2] - (multiplier * tempArray[j][j2]);
					}
				}
			}

		}
		double total = 1.0;
		for (int i = 0; i < tempArray.length; i++) {
			for (int j = 0; j < tempArray[0].length; j++) {
				if (i == j) {
					total *= tempArray[i][j];
				}
			}
		}
		determinant = Math.pow(-1, r) * total;
		return determinant;
	}
	
	
	public static double[][] inverseClass1 = new double[2][2];
	public static double[][] inverseClass2 = new double[2][2];
	
	
	public static double[][] determineClassification(double[][] matrix){
		double[][] g=new double[5][1];
		double[][] temp1=new double[2][1];
		double[][] temp2=new double[2][1];
		temp1[0][0]=(matrix[0][0]-class1Mean[0][0]);
		temp1[1][0]=(matrix[1][0]-class1Mean[1][0]);
		temp2[0][0]=(matrix[0][0]-class2Mean[0][0]);
		temp2[1][0]=(matrix[1][0]-class2Mean[1][0]);
		
		double[][] g1=scalarMult(mult2Matrices(mult2Matrices(transpose(temp1),inverseClass1),temp1),(-.5));
		g1[0][0]-=(.5*Math.log(class1Determinant));
		double[][] g2=scalarMult(mult2Matrices(mult2Matrices(transpose(temp2),inverseClass2),temp2),(-.5));
		g2[0][0]-=(.5*Math.log(class2Determinant));
		g[0][0]=g1[0][0];
		g[1][0]=g2[0][0];
		if(g[0][0]==g[1][0])
			g[2][0]=-999.999;
		else
			if(g[0][0]>g[1][0])
				g[2][0]=1.0;
		else
			g[2][0]=2.0;
		g[3][0]=matrix[0][0];
		g[4][0]=matrix[1][0];
		return g;
	}
	
	public static void boundries(double[][] matrix){
		double[][] g=new double[5][1];
		double[][] temp1=new double[2][1];
		double[][] temp2=new double[2][1];
		temp1[0][0]=(matrix[0][0]-class1Mean[0][0]);
		temp1[1][0]=(matrix[1][0]-class1Mean[1][0]);
		temp2[0][0]=(matrix[0][0]-class2Mean[0][0]);
		temp2[1][0]=(matrix[1][0]-class2Mean[1][0]);
		
		double[][] g1=scalarMult(mult2Matrices(mult2Matrices(transpose(temp1),inverseClass1),temp1),(-.5));
		g1[0][0]-=(.5*Math.log(class1Determinant));
		double[][] g2=scalarMult(mult2Matrices(mult2Matrices(transpose(temp2),inverseClass2),temp2),(-.5));
		g2[0][0]-=(.5*Math.log(class2Determinant));
		if(Math.abs(g1[0][0]-g2[0][0])<.0005)
			System.out.println(matrix[0][0]+"\t"+matrix[1][0]);
	}
	
	public static double[][] augmentStep1(double[][] p){
		int s=p.length;
		double [][] aug=new double [s][s];
		for(int i=0;i<s;i++){
			int coeff=s-1;
			for(int j=0;j<s;j++){
				aug[i][j]=Math.pow(p[i][0],coeff);
				coeff--;
			}
		}
		return aug;
	}
	
	
	
	
	public static double[][] matrixInverse(double[][] a) throws Exception {
		double[][] c = augmentedArray(a, multIdentMatrix(a.length));
		int E = 1;
		double max = 0;
		int pivot = 0;
		double[][] temp1 = new double[1][c[0].length];
		double[][] temp2 = new double[1][c[0].length];
		double[][] temp3 = new double[1][c[0].length];

		for (int j = 0; j < c.length; j++) {
			for (int p = j; p < c.length; p++) {
				if (Math.abs(c[p][j]) > max) {
					max = Math.abs(c[p][j]);
					pivot = p;
				}
			}
			if (max == 0) {
				E = 0;
				System.out.println("E = 0: System Exit");
				System.exit(0);
			}
			if (pivot > j) {
				for (int p = 0; p < c[0].length; p++) {
					temp1[0][p] = c[pivot][p];
					temp2[0][p] = c[j][p];
				}
				for (int p = 0; p < c[0].length; p++) {
					c[j][p] = temp1[0][p];
					c[pivot][p] = temp2[0][p];
				}
			}
			max = 0;
			pivot = 0;
			for (int p = 0; p < c[0].length; p++) {
				temp3[0][p] = c[j][p];
			}
			scalarMult(temp3, (1 / c[j][j]));
			for (int p = 0; p < c[0].length; p++) {
				c[j][p] = temp3[0][p];
			}
			for (int i = 0; i < c.length; i++) {
				if (i != j) {
					double multiplier = c[i][j];
					for (int j2 = 0; j2 < c[0].length; j2++) {
						c[i][j2] = c[i][j2] - (multiplier * c[j][j2]);
					}
				}
			}
		}
		double[][] d = new double[a.length][a[0].length];
		for (int i = 0; i < a.length; i++) {
			for (int j = a.length; j < c[0].length; j++) {
				d[i][j - a.length] = c[i][j];
			}
		}

		return d;
	}

	private static double[][] augmentedArray(double[][] array,	double[][] ident) {
		int s=array.length;
		double [][] temp=new double[s][s*2];
		for(int i=0;i<s;i++){
			for(int j=0;j<s;j++){
				temp[i][j]=array[i][j];
			}
		}
		for(int i=0;i<s;i++){
			for(int j=s;j<s*2;j++){
				temp[i][j]=ident[i][j-s];
			}
		}
		return temp;
	}
	public static double [] randoms(){
		double [] random1024=new double[1024];
		for(int i=0;i<1024;i++)
			random1024[i]=Math.random();
		return random1024;
	}
	public static double[][] fOfX(double[] randoms, int k){
		double[][] answer=new double[1024][6];
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=5;i++){
				y+=(Math.sin(2*Math.PI*((2*i)-1)*randoms[x]))/((2*i)-1);
			}
			answer[x][0]=randoms[x];
			answer[x][1]=y;
		}
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=10;i++){
				y+=(Math.sin(2*Math.PI*((2*i)-1)*randoms[x]))/((2*i)-1);
			}
			answer[x][2]=randoms[x];
			answer[x][3]=y;
		}
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=1000;i++){
				y+=(Math.sin(2*Math.PI*((2*i)-1)*randoms[x]))/((2*i)-1);
			}
			answer[x][4]=randoms[x];
			answer[x][5]=y;
		}
		return answer;
	}
	
	public static double[][] gOfX(double[] randoms, int k){
		double[][] answer=new double[1024][6];
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=5;i++){
				y+=(Math.sin(2*Math.PI*((2*i))*randoms[x]))/((2*i));
			}
			answer[x][0]=randoms[x];
			answer[x][1]=y;
		}
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=10;i++){
				y+=(Math.sin(2*Math.PI*((2*i))*randoms[x]))/((2*i));
			}
			answer[x][2]=randoms[x];
			answer[x][3]=y;
		}
		for(int x=0;x<randoms.length;x++){
			double y=0.0;
			for(int i=1;i<=1000;i++){
				y+=(Math.sin(2*Math.PI*((2*i))*randoms[x]))/((2*i));
			}
			answer[x][4]=randoms[x];
			answer[x][5]=y;
		}
		return answer;
	}
	
	public static void PSD(double[] gs){
		Complex[] gsCN = new Complex[gs.length];
		for(int i = 0; i < gs.length; i++){
			gsCN[i] = new Complex(gs[i],0);
		}
		Complex[] fftGScomplex = FFT.fourier(gsCN, 1);
		for(int i =0; i < fftGScomplex.length; i++){
			System.out.println(fftGScomplex[i].getR());
		}
		Complex[] fftGsCNs = new Complex[gs.length];
		for(int i = 0; i < gs.length; i++)
			fftGsCNs[i] = fftGScomplex[i].conjugate();
		for(int i = 0; i < gs.length; i++)
			gsCN[i] = fftGScomplex[i].times(fftGsCNs[i]);
		double[] realsGS = new double[gs.length];
		for(int i = 0; i < gs.length; i++){
			realsGS[i] = gsCN[i].getR();
		}
	}
	
	public static ArrayList<Double> posOnly(double[] temp){
		ArrayList<Double> answer=new ArrayList<Double>();
		for(int i=0;i<temp.length;i++){
			if(temp[i]>=0){
				answer.add(temp[i]);
			}
		}
		return answer;
	}
	public static double[][] PSD(){
		double[][]gsTemp=gOfX(randoms(),4);
		double[] gs=new double[1024];
		double[][] answer=new double[1024][2];
		for(int i=0;i<1024;i++){
			if(gsTemp[i][5]>=0){
				gs[i]=gsTemp[i][5];
			}
			else
				gs[i]=0;
		}
		Complex[] gscomplex = new Complex[gs.length];
		for(int i = 0; i < gs.length; i++){
			gscomplex[i] = new Complex(gs[i],0);
		}
		Complex[] fftGScomplex = FFT.fourier(gscomplex, 0);
		for(int i =0; i < fftGScomplex.length; i++){
			System.out.println(fftGScomplex[i].getR());
		}
		Complex[] fftGScon = new Complex[gs.length];
		for(int i = 0; i < gs.length; i++)
			fftGScon[i] = fftGScomplex[i].conjugate();
		for(int i = 0; i < gs.length; i++)
			gscomplex[i] = fftGScomplex[i].times(fftGScon[i]);
		for(int i = 0; i < gs.length; i++){
			answer[i][0]= gsTemp[i][4];
			answer[i][1] = gscomplex[i].getR();
		}
		return answer;
	}
	
	
	
	
	public static double[][] fsFFT(){
		double[] fs = randoms();
		double[][] temp=fOfX(fs,5);
		double[] fsY=new double[1024];
		double[][] answer=new double[1024][2];
		for(int i=0;i<1024;i++){
			if(temp[i][5]>=0)
				fsY[i]=temp[i][5];
			else
				fsY[i]=0.0;
		}
		Complex[] fscomplex = new Complex[fsY.length];
		for(int i = 0; i < fsY.length; i++){
			fscomplex[i] = new Complex(fsY[i],0);		
		}
		
		Complex[] fftFScomplex = FFT.fourier(fscomplex, 1);
		
		for(int i =0; i < fftFScomplex.length; i++){
	//		System.out.println(fftFScomplex[i].getR());
		}
		
		Complex[] fftFScon = new Complex[fs.length];
		for(int i = 0; i < fs.length; i++){
			fftFScon[i] = fftFScomplex[i].conjugate();
			
		}
		for(int i = 0; i < fs.length; i++){
			fscomplex[i] = fftFScomplex[i].times(fftFScon[i]);
		}
		double[] realsFS = new double[fs.length];
		for(int i = 0; i < fs.length; i++){
			answer[i][0]=temp[i][4];
			answer[i][1] = fscomplex[i].getR();
		}
		return answer;
	}
	
	
	public static void main(String []args) throws Exception {
		double [] random1024=randoms();
		double [][] p= {{-2, -6}, {-1, 2}, {0, -4}, {1,-3}};
		double [][] aug=augmentStep1(p);
		double [][]augAns={{-6},{2},{-4},{-3}};
		double[] testFFT={26160.0,
				19011.0,
				18757.0,
				18405.0,
				17888.0,
				14720.0,
				14285.0,
				17018.0,
				18014.0,
				17119.0,
				16400.0,
				17497.0,
				17846.0,
				15700.0,
				17636.0,
				17181.0};
		double det=determinant(aug);
		double[] test={0.2,0.3,0.4};
		Complex cn=new Complex(5,2);
		Complex []testAnswers=FFT.fft(testFFT);
		printArray(PSD());
		//printArray(aug);
		//aug=matrixInverse(aug);
		//printArray(aug);
	//	System.out.println(det);
//		double[][] augmented=new double[4][5];
//		for(int i=0;i<4;i++){
//			for(int j=0;j<4;j++){
//				augmented[i][j]=aug[i][j];
//			}
//		}
//		for(int i=0;i<4;i++)
//			augmented[i][4]=augAns[i];
//		printArray(augmented);
		//printArray(mult2Matrices(aug,augAns));
	//	double[] answers=gauss(aug,augAns);
		//printArray(answers);
	//	printArray(gOfX(random1024,5));
	}
}